#include "stdafx.h"
static const int PORT = 9995;

GameLogic::GameLogic()
{
	m_pEventBase = NULL;
	m_pLlistener = NULL;
	m_pSignal_event  = NULL;
	m_pSignal_event1 = NULL;
	m_pSignal_event2 = NULL;
}

GameLogic::~GameLogic()
{

}

void GameLogic::conn_writecb(struct bufferevent *bev, void *user_data)
{
	struct evbuffer *output = bufferevent_get_output(bev);
	if (evbuffer_get_length(output) == 0)
	{
		printf("flushed answer\n");
		bufferevent_free(bev);
	}
}

void GameLogic::conn_readcb(struct bufferevent *bev, void *user_data)
{
	//struct evbuffer *input = bufferevent_get_input(bev);
	//struct evbuffer *output = bufferevent_get_output(bev);
	//int n = 0;
	//char buf[MAX_LENGTH] = { 0 };
	//CPlayer* player = (CPlayer*)user_data;
	//if (!player)
	//	return;
	//int length = evbuffer_get_length(input);
	//evbuffer_read(input, player->m_fd, MAX_LENGTH);
	/*long long ident = 0;
	evbuffer_remove(input, &ident, sizeof(long long));
	evbuffer_drain(input, -1 * sizeof(long long));

	evbuffer_remove(input, &ident, sizeof(long long));

	length = evbuffer_get_length(input);
	SIZE_ST size = 0;
	evbuffer_remove(input, &size, sizeof(SIZE_ST));
	length = evbuffer_get_length(input);*/


	/*while ((n = bufferevent_read(bev, buf, MAX_LENGTH) > 0))
	{
	printf("conn_readcb =  %s\n", buf);

	CNetPacket packet(buf, MAX_LENGTH);
	const char* str = NULL;
	packet >> str;
	int d = 0;
	packet >> d;
	printf("pNet size = %d \n", packet.m_header.nPackSize);
	printf("pNet msgId = %d \n", packet.m_Msg.m_nMsgId);
	printf("pNet str = %s \n", str);
	printf("pNet d = %d \n", d);
	packet.clear();
	}*/
}

void GameLogic::conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
	if (events & BEV_EVENT_EOF)
	{
		printf("Connection closed.\n");
	}
	else if (events & BEV_EVENT_ERROR)
	{
		printf("Got an error on the connection: %s\n", strerror(errno));
	}
	CPlayer* player = (CPlayer*)user_data;
	CPlayerManager::instance()->offline(player);
	bufferevent_free(bev);
}

void GameLogic::signal_cb(evutil_socket_t sig, short events, void *user_data)
{
	GameLogic* pGameLogic = (GameLogic*)user_data;
	if (!pGameLogic)
		return;
	m_boRun = false;
	timeval val;
	val.tv_sec = 2;
	val.tv_usec = 0;
	event_base_loopexit(pGameLogic->m_pEventBase, &val);
}

void GameLogic::listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data)
{
	struct event_base *base = (struct event_base *)user_data;
	struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	if (!bev)
	{
		fprintf(stderr, "Error constructing bufferevent!");
		event_base_loopbreak(base);
		return;
	}
	CPlayer* player = new CPlayer();
	player->m_fd = fd;
	player->m_bev = bev;
	CPlayerManager* pMa = CPlayerManager::instance();
	pMa->online(player);

	bufferevent_setcb(bev, GameLogic::conn_readcb, NULL, GameLogic::conn_eventcb, (void *)player);
	bufferevent_enable(bev, EV_READ | EV_WRITE);

}

void GameLogic::run()
{

#ifdef WIN32
	WSADATA wsa_data;
	WSAStartup(0x0201, &wsa_data);
#endif
	m_pEventBase = event_base_new();
	if (!m_pEventBase)
	{
		fprintf(stderr, "Could not initialize libevent!\n");
		return ;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	m_pLlistener = evconnlistener_new_bind(m_pEventBase, GameLogic::listener_cb, (void *)m_pEventBase,
		LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
		(struct sockaddr*)&sin,
		sizeof(sin));
	if (!m_pLlistener)
	{
		fprintf(stderr, "Could not create a listener!\n");
		return ;
	}
	m_pSignal_event = evsignal_new(m_pEventBase, SIGINT, signal_cb, (void *)this);
	if (!m_pSignal_event || event_add(m_pSignal_event, NULL) < 0)
	{
		fprintf(stderr, "Could not create/add a signal event!\n");
		return ;
	}
	m_pSignal_event1 = evsignal_new(m_pEventBase, SIGBREAK, signal_cb, (void *)this);
	if (!m_pSignal_event1 || event_add(m_pSignal_event1, NULL) < 0)
	{
		fprintf(stderr, "Could not create/add a signal event!\n");
		return ;
	}
	m_pSignal_event2 = evsignal_new(m_pEventBase, SIGTERM, signal_cb, (void *)this);
	if (!m_pSignal_event2 || event_add(m_pSignal_event2, NULL) < 0)
	{
		fprintf(stderr, "Could not create/add a signal event!\n");
		return ;
	}
	m_Handle = CreateThread(NULL, 0, &GameLogic::mainRun, NULL, 0, NULL);
	event_base_dispatch(m_pEventBase);
	stop();
}

void GameLogic::stop()
{
	printf("GameLogic Stop ........ \n");
	evconnlistener_free(m_pLlistener);
	event_free(m_pSignal_event);
	event_free(m_pSignal_event1);
	event_free(m_pSignal_event2);
	event_base_free(m_pEventBase);
	CloseHandle(m_Handle);
}

DWORD WINAPI GameLogic::mainRun(LPVOID lp)
{
	size_t length = 0;
	evbuffer* input = NULL;
	SIZE_ST packetSize = 0;
	char buf[MAX_LENGTH] = { 0 };
	char tmp;
	NetPacketHeader ident;
	int nCount = 0;
	

	while (1)
	{
		if (!m_boRun)
		{
			for (MapPlayerSocketPtr::iterator it = CPlayerManager::instance()->m_MapPlayer.begin(); it != CPlayerManager::instance()->m_MapPlayer.end(); )
			{
				 CPlayer* pPlayer = it->second;
				if (!pPlayer)
					continue;
				it++;
				bufferevent_free(pPlayer->m_bev);
				CPlayerManager::instance()->offline(pPlayer);
			}
			break;
		}
		else
		{

			for (MapPlayerSocketPtr::iterator it = CPlayerManager::instance()->m_MapPlayer.begin(); it != CPlayerManager::instance()->m_MapPlayer.end(); it++)
			{
				const CPlayer* pPlayer = it->second;
				if (!pPlayer)
					continue;
				if (pPlayer->m_bev == NULL)
					continue;

				input = bufferevent_get_input(pPlayer->m_bev);
				evbuffer_lock(input);
				length = evbuffer_get_length(input);
				
				nCount = 0;
				while (length > sizeof(NetPacketHeader) && nCount < 64)
				{
					memset(&ident, 0, sizeof(NetPacketHeader));
					evbuffer_copyout(input, &ident, sizeof(NetPacketHeader));
					if (ident.llIdent != nHeaderFlag)
					{
						evbuffer_remove(input, &tmp, 1);
						length = evbuffer_get_length(input);
					}
					else
					{
						packetSize = ident.nPackSize;
						length = evbuffer_get_length(input);
						if (packetSize > (length + sizeof(NetPacketHeader)))
						{
							length = evbuffer_get_length(input);
							break;
						}
						length = evbuffer_get_length(input);
						memset(buf, 0, MAX_LENGTH);
						if (packetSize > MAX_LENGTH)
						{
#ifdef _DEBUG
							assert(false);
#endif
							evbuffer_drain(input, packetSize);
						}
						evbuffer_remove(input, buf, packetSize);
						CNetPacket* packet = new CNetPacket(buf, packetSize);
						printf("packet msgId =  %d \n", packet->m_Msg.m_nMsgId);
						packet->clear();
						delete packet;
						packet = NULL;
					}
					nCount++;
				}
				evbuffer_unlock(input);
			}
		}
		printf("mainRun runing ....\n");
		Sleep(1);
	}

	return 0;
}

bool GameLogic::m_boRun = true;
